package com.yinhanshi.s3test.downlaod;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import com.amazonaws.HttpMethod;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.yinhanshi.s3test.utils.FileIOUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;

/**
 * 标题：文件下载
 * 作者：yinhanshi .
 * 时间：2020/3/5 .
 */
public class Downloader {

    private static final long MIN_DEFAULT_PART_SIZE = 1 * 1024 * 1024; // 1M

    private static final String TAG = "Simpl3r";
    private static final String PREFS_NAME = "preferences_simpl3r";
    private static final String PREFS_UPLOAD_ID = "_uploadId";
    private static final String PREFS_ETAGS = "_etags";
    private static final String PREFS_ETAG_SEP = "~~";

    private AmazonS3Client s3Client;
    private String s3bucketName;
    private String s3key;
    private File file;

    private SharedPreferences prefs;
    private long partSize = MIN_DEFAULT_PART_SIZE;
    private DownloadProgressListener progressListener;
    private long bytesDownloaded = 0;   //文件已下载长度
    private long fileTotalLength = 0;   //文件总长度
    private boolean userInterrupted = false;
    private boolean userAborted = false;

    /**
     * 下载管理类
     *
     * @param context         上下文
     * @param s3Client        s3Client
     * @param s3bucketName    bucketName
     * @param s3key           文件key
     * @param file            文件存储路径
     * @param fileTotalLength 文件总大小
     */
    public Downloader(Context context, AmazonS3Client s3Client, String s3bucketName, String s3key, File file, long fileTotalLength) {
        this.s3Client = s3Client;
        this.s3key = s3key;
        this.s3bucketName = s3bucketName;
        this.file = file;
        this.fileTotalLength = fileTotalLength;
        prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    /**
     * 获取文件的可访问路径
     *
     * @return 文件的 url
     */
    public String getFileUrl() {
        //设置过期时间 9700小时
        java.util.Date expiration = new java.util.Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += 1000L * 60 * 60 * 24 * 7;
        expiration.setTime(expTimeMillis);
        //创建根据桶名称和key查询在s3中url的请求对象
        GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(s3bucketName, s3key)
                .withMethod(HttpMethod.GET)
                .withExpiration(expiration);
        URL url = s3Client.generatePresignedUrl(urlRequest);
        return url.toString();
    }

    /**
     * 以分片形式进行文件的下载操作
     */
    public void start() {
        //若文件不存在，则创建
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //初始化参数
        userInterrupted = false;
        userAborted = false;
        bytesDownloaded = file.length();
        long endIndex = Math.min(bytesDownloaded + MIN_DEFAULT_PART_SIZE, fileTotalLength);
        downloadFile(s3bucketName, s3key, bytesDownloaded, endIndex);
    }

    /**
     * 分片下载
     * 需要传桶名称,文件key,开始字节数,结束字节数,第几片分片
     * 其中桶名称和文件key用于下载,指定开始和结束的字计数
     * 第几片分片用于存储下载后的分片文件
     * result.getSuccess为成功失败状态
     * result.getData为返回的MultipartFile
     *
     * @param bucketName 桶名
     * @param key        文件标识
     * @param startIndex 开始字节
     * @param endIndex   结束字节
     * @return InputStream
     */
    public void downloadFile(String bucketName, String key, long startIndex, long endIndex) {
        Log.i("start request:", "[bucketName" + bucketName + ",key:" + key + ",startIndex:" + startIndex + ",endIndex:" + endIndex + "]");
        long startTime = Calendar.getInstance().getTimeInMillis();
        Date startDate = new Date(startTime);
        Log.i("S3分片下载开始时间为:", startDate.toString());
        S3Object objectPortion;
        try {
            //下载指定范围的对象
            GetObjectRequest rangeObjectRequest = new GetObjectRequest(bucketName, key)
                    .withRange(startIndex, endIndex);
            objectPortion = s3Client.getObject(rangeObjectRequest);
            //保存分片文件到文件系统
            if (null != objectPortion) {
                //打印时间
                long endTime = Calendar.getInstance().getTimeInMillis();
                Date endDate = new Date(endTime);
                Log.i("S3下载结束时间为:", endDate.toString());
                Log.i("S3下载总共用的秒数:", (endTime - startTime) / 1000.0 + "");
                Log.i("S3下载速度(mb/s),文件大小/时间:", ((objectPortion.getObjectContent().available() / 1024.0 / 1024.0) / ((endTime - startTime) / 1000.0)) + "mb/s");
                //将 InputStream 写入文件
                saveToFile(objectPortion.getObjectContent());
            }
        } catch (Exception e) {
            Log.e("========request:", "[" + bucketName + key + startIndex + endIndex + "] errorMessage:[下载文获取文件流异常:" + e.getMessage() + "]");
        }
    }

    /**
     * 写入文件
     *
     * @param objectContent InputStream
     */
    public void saveToFile(InputStream objectContent) {
        // 写入文件的监听
        FileIOUtils.OnProgressUpdateListener listener = new FileIOUtils.OnProgressUpdateListener() {
            @Override
            public void onProgressUpdate(double progress) {
                if (100 == progress) {   //文件写入操作完成
                    Log.i("progress", progress + "");

                }
            }
        };
        FileIOUtils.writeFileFromIS(file, objectContent, true, listener);

        bytesDownloaded = bytesDownloaded + MIN_DEFAULT_PART_SIZE;
        if (bytesDownloaded < fileTotalLength) {
            // 文件未完成下载，继续下载操作
            long endIndex = Math.min(bytesDownloaded + MIN_DEFAULT_PART_SIZE, fileTotalLength);
            // 计算当前进度，并发送通知
            float fpercent = ((bytesDownloaded * 100) / fileTotalLength);
            int percent = Math.round(fpercent);
            if (progressListener != null) {
                progressListener.progressChanged(bytesDownloaded, percent);
            }
            // 用户终止下载操作
            if (userInterrupted) {
                s3Client.shutdown();
                return;
            }
            // 继续剩余下载任务
            downloadFile(s3bucketName, s3key, bytesDownloaded + 1, endIndex);
        } else {
            // 文件已完成下载
            if (progressListener != null) {
                progressListener.progressChanged(bytesDownloaded, 100);
            }
        }

    }

    public void interrupt() {
        userInterrupted = true;
    }

    public void setProgressListener(DownloadProgressListener progressListener) {
        this.progressListener = progressListener;
    }

    public interface DownloadProgressListener {
        public void progressChanged(long bytesDownloaded, int percentDownloaded);
    }

}
